package com.sugon.controller.device;

import cn.afterturn.easypoi.entity.vo.TemplateExcelConstants;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.sugon.annotation.AutoLog;
import com.sugon.annotation.DataFilter;
import com.sugon.annotation.NonBusinessParamValid;
import com.sugon.dao.SysUserDao;
import com.sugon.entity.*;
import com.sugon.entity.vo.TicketLiveImageGroup;
import com.sugon.modules.device.consts.DevRepairTicketStage;
import com.sugon.modules.device.service.IDeviceRepairManager;
import com.sugon.modules.sys.consts.SysDeptConst;
import com.sugon.modules.sys.consts.SysRole;
import com.sugon.service.*;
import com.sugon.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 维修工单管理Controller
 *
 * @author sugon
 * @date 2019-07-12 11:39:29
 */
@Slf4j
@Controller
@RequestMapping("devmaintenwork")
public class DevMaintenWorkController {

    @Autowired
    private DevMaintenWorkService devMaintenWorkService;
    @Autowired
    private IDeviceRepairManager deviceRepairManager;
    @Autowired
    private SysUserDao userDao;
    @Autowired
    private TicketLiveImageService ticketLiveImageService;
    @Autowired
    private SysConfigService configService;
    @Resource
    private DevMaintenThirdpartyCbService thirdpartyCbService;
    @Resource
    private DeviceInfoService deviceService;
    @Resource
    private DevRepairRecordService devRepairRecordService;

    /**
     * thinworks平台回调
     *
     * @param callbackParam
     * @return
     */
    @NonBusinessParamValid
    @RequestMapping("/callback")
    @ResponseBody
    public R callback(@Validated @RequestBody DevMaintenThirdpartyCbEntity callbackParam, BindingResult bindingResult) {
        log.info("监听到thinworks平台回调，回调内容：" + JSON.toJSONString(callbackParam));
        /*
            1、是数据的完整性：产线码、设备码
            2、确定产线码和设备码的有效性
            3、确定回调数据属于维修的哪个阶段：上报、开始维修、结束维修 ，以及是否重复
         */
        // 确定产线码和设备码的有效性
        /*
            设备分为机加设备+铸造设备
            机加设备：产线 + 设备码 -> 设备唯一码，根据设备唯一码匹配设备
            铸造设备：ERMS中的设备编码，CQA-XXXXX -> 根据设备编码匹配设备
         */
        // 优先根据第三方回调传递的业务ID查询是否有已知记录
        String devId = null, devType = null;
        String busId = callbackParam.getBusId();
        if (StrUtil.isNotEmpty(busId)) {
            List<DevMaintenThirdpartyCbEntity> cbRecordList = thirdpartyCbService.queryByBusId(busId);
            if (CollectionUtil.isNotEmpty(cbRecordList)) {
                devId = cbRecordList.get(0).getDevId();
                // 相同业务单号的维修分类保持一致：维修分类
                callbackParam.setCategory(cbRecordList.get(0).getCategory());
                callbackParam.setErmsBusId(cbRecordList.get(0).getErmsBusId());
            }
        }
        // 如果没有匹配的回调记录，则根据设备编码(一般为ERMS系统的设备编码)进行匹配
        if (StrUtil.isEmpty(devId)) {
            // 优先识别下铸造设备
            String machineCode = callbackParam.getMachineCode();
            if (StrUtil.isNotEmpty(machineCode)) {
                DeviceInfoEntity device = deviceService.getInfoByDevCode(machineCode);
                if (device != null) {
                    devId = device.getId();
                    devType = device.getDevTypeS();
                }
            }
        }
        // 继续使用产线代码+设备编码 -> 设备底层唯一码进行匹配
        if (StrUtil.isEmpty(devId)) {
            DeviceInfoEntity device = deviceService.queryByDevLastCode(callbackParam.getLineCode(), callbackParam.getMachineCode());
            if (device != null) {
                devId = device.getId();
                devType = device.getDevTypeS();
            }
        }
        // 到此为止，如果仍未匹配到，说明是无效的记录，不允许走后续逻辑
        if (!StrUtil.isAllNotEmpty(devId)) {
            return R.error("根据产线码和设备码无法识别具体设备，请确认！");
        }
        callbackParam.setDevId(devId);
        callbackParam.setDeviceType(devType);
        callbackParam.setContent(JSON.toJSONString(callbackParam));
        return thirdpartyCbService.addThirdPartyCbData(callbackParam) ? R.ok() : R.error("回调失败");
    }

    /**
     * 获取当前维修工单的协助人员列表
     * 如果当前为节点1，那么返回当前车间的设备机电工程师列表
     */
    @RequestMapping("/assistPersonList")
    @ResponseBody
    public R listAssistPerson(@RequestParam String id) {
        DevMaintenWorkEntity work = devMaintenWorkService.queryObject(id);
        if (work == null) {
            return R.error("非法工单");
        }
        // 声明协助人列表
        List<SysUserEntity> assistPersonList;
        int handleNode = work.getHandleNode();
        if (handleNode == 1) {
            assistPersonList = userDao.queryByWorkshopAndRole(ShiroUtils.getWorkshop(), SysRole.CJJDSBGCS.getRoleId());
        } else if (handleNode == 2) {
            assistPersonList = userDao.queryByWorkshopAndRole(SysDeptConst.ZZC_CODE, SysRole.ZZCJDSBGCS.getRoleId());
        } else {
            assistPersonList = new ArrayList<>();
        }
        return R.ok().put("assistPersonList", assistPersonList);
    }

    /**
     * 查看列表
     */
    @RequestMapping("/list")
//    @RequiresPermissions("devmaintenwork:list")
    @ResponseBody
    @DataFilter(deptAlias = "DI.DEV_FARM", userAlias = {"DMW.REPAIR_USER", "DMW.UPLOAD_ID"})
    public R list(@RequestParam Map<String, Object> params) {
        // 调整开始时间和结束时间
        String beginTime = cn.hutool.core.map.MapUtil.getStr(params, "beginTime");
        if (StrUtil.isNotEmpty(beginTime)) {
            params.put("beginTime", beginTime + " 0:00:00");
        }
        String endTime = cn.hutool.core.map.MapUtil.getStr(params, "endTime");
        if (StrUtil.isNotEmpty(endTime)) {
            params.put("endTime", endTime + " 23:59:59");
        }

        //查询列表数据
        Query query = new Query(params);
        List<DevMaintenWorkEntity> devMaintenWorkList = devMaintenWorkService.queryList(query);
        int total = devMaintenWorkService.queryTotal(query);
        PageUtils pageUtil = new PageUtils(devMaintenWorkList, total, query.getLimit(), query.getPage());

        return R.ok().put("page", pageUtil);
    }

    @RequiresPermissions("devmaintenwork:export")
    @RequestMapping("/export")
    @ResponseBody
    public void export(@RequestParam Map<String, Object> params, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response) {
        // 设置导出EXCEL模板名称
        modelMap.put(TemplateExcelConstants.FILE_NAME, "设备维修工单导出_" + DateUtil.format(DateUtil.date(), "yyyyMMdd"));
        // 设置导出模板参数
        TemplateExportParams templateExportParams = new TemplateExportParams(configService.getPoiTemplatePath() + "deviceRepairTicketTemplate.xlsx");
        templateExportParams.setColForEach(true);
        modelMap.put(TemplateExcelConstants.PARAMS, templateExportParams);
        // 获取设备维护计划预览模板数据
        Map<String, Object> mapData = MapUtil.newHashMap(1);
        // 获取预防性维护计划数据
        mapData.put("list", devMaintenWorkService.prepareExportData(params));
        modelMap.put(TemplateExcelConstants.MAP_DATA, mapData);
        PoiBaseView.render(modelMap, request, response, TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
    }

    /**
     * 查看信息
     */
    @RequestMapping("/info/{id}")
//    @RequiresPermissions("devmaintenwork:info")
    @ResponseBody
    public R info(@PathVariable("id") String id) {
        DevMaintenWorkEntity devMaintenWork = devMaintenWorkService.queryObject(id);
        // 设置工单现场图片：进行分组
        List<TicketLiveImageEntity> ticketLiveImages = ticketLiveImageService.queryList(id, "REPAIR");
        if (CollectionUtil.isNotEmpty(ticketLiveImages)) {
            Map<String, List<TicketLiveImageEntity>> temGroup = ticketLiveImages.stream().collect(Collectors.groupingBy(TicketLiveImageEntity::getGroupName));
            Set<Map.Entry<String, List<TicketLiveImageEntity>>> entries = temGroup.entrySet();
            List<TicketLiveImageGroup> ticketLiveImageGroup = CollectionUtil.newArrayList();
            for (Map.Entry<String, List<TicketLiveImageEntity>> entry : entries) {
                ticketLiveImageGroup.add(new TicketLiveImageGroup(entry.getKey(), entry.getValue()));
            }
            devMaintenWork.setTicketLiveImageGroup(ticketLiveImageGroup);
        }
        return R.ok().put("devMaintenWork", devMaintenWork);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    @RequiresPermissions("devmaintenwork:save")
    @ResponseBody
    @AutoLog("设备故障报修")
    public R save(@RequestBody DevMaintenWorkEntity devMaintenWork) {
        devMaintenWork.setUploadId(ShiroUtils.getUserEntity().getUserId());
        devMaintenWork.setUploadName(ShiroUtils.getUserEntity().getUserName());
        devMaintenWork.setUploadDate(DateUtil.date());
        return deviceRepairManager.callRepair(devMaintenWork) ? R.ok() : R.error();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    @RequiresPermissions("devmaintenwork:update")
    @ResponseBody
    @AutoLog("维修工单修改")
    public R update(@RequestBody DevMaintenWorkEntity devMaintenWork) {
        devMaintenWorkService.update(devMaintenWork);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    @RequiresPermissions("devmaintenwork:delete")
    @ResponseBody
    @AutoLog("维修工单删除")
    public R delete(@RequestBody String[] ids) {
        devMaintenWorkService.deleteBatch(ids);

        return R.ok();
    }

    /**
     * 查看所有列表
     */
    @RequestMapping("/queryAll")
    @ResponseBody
    public R queryAll(@RequestParam Map<String, Object> params) {

        List<DevMaintenWorkEntity> list = devMaintenWorkService.queryList(params);

        return R.ok().put("list", list);
    }

    /**
     * 当前处理人员不能在规定时间内处理完，上报到上一级申请协助处理
     *
     * @param id
     * @param assistPersonId
     * @return
     */
    @AutoLog("维修工单上报到下一级")
    @RequestMapping("/report")
    @ResponseBody
    public R reportWork(@RequestParam String id, @RequestParam String assistPersonId) {
        DevMaintenWorkEntity work = devMaintenWorkService.queryObject(id);
        if (work == null) {
            return R.error("工单不存在，请确认！");
        }
        if (work.getDevStatus() != DevRepairTicketStage.START_REPAIR) {
            return R.error("只有处于[维修中]的工单才可以申请上级协助处理！");
        }
//        if (!ShiroUtils.getUserId().equals(work.getRepairUser())) {
//            return R.error("只可以处理分配给自己的工单！");
//        }
//        devMaintenWorkService.report(id);
        return deviceRepairManager.report(work, assistPersonId) ? R.ok() : R.error();
    }

    /**
     * 获取维修组成员id
     */
    @RequestMapping("/repairUser")
    @ResponseBody
    public R getRepairUser() {
        List userList = devMaintenWorkService.getRepairUser();
        return R.ok().put("repairUserList", userList);
    }

    /**
     * 维修人员确定执行
     *
     * @return
     */
    @RequestMapping("/orderSure")
    @ResponseBody
    @AutoLog("维修人员确定")
    public R checkSure(@RequestParam String id) {
        /*
        1、更新派工单
        2、更新维修工单状态
        3、开启30分钟或者120分钟倒计时
         */
        // 校验工单是否存在
        DevRepairRecordEntity devMaintenWork = devRepairRecordService.queryObject(id);
        if (devMaintenWork == null) {
            return R.error("工单信息不存在，请确认！");
        }
        // 校验是否处于 待开始状态
        Integer ticketStatus = devMaintenWork.getDevStatus();
        if (ticketStatus != null && ticketStatus != DevRepairTicketStage.CALL_REPAIR) {
            return R.error("只可以确认维修处于[待维修]状态的工单！");
        }
        devMaintenWork.setRepairUser(ShiroUtils.getUserId());
        return deviceRepairManager.confirmRepair(devMaintenWork) ? R.ok() : R.error();
    }

    @RequestMapping("completeRepair")
    @ResponseBody
    @AutoLog("维修工完成维修")
    public R endProcess(@RequestParam String id) {
        DevRepairRecordEntity repairTicket = devRepairRecordService.queryObject(id);
        if (repairTicket == null) {
            return R.error("无效工单");
        }
        // 如果没有结束维修时间，那么设置为当前系统时间
        Date endRepairTime = repairTicket.getRepairEndDate();
        if (endRepairTime == null) {
            endRepairTime = DateUtil.date();
            repairTicket.setRepairEndDate(endRepairTime);
        }
        // 结束维修时，维修时长不得小于5分钟
        if (DateUtil.between(repairTicket.getRepairStartDate(), endRepairTime, DateUnit.MINUTE) < 5) {
            return R.error("维修时长不得小于5分钟！");
        }
        return deviceRepairManager.completeRepair(repairTicket) ? R.ok().put("over", 1) : R.error();
    }

    @RequestMapping("/Auxiliary")
    @ResponseBody
    public R auxiliary(String id) {
        int i = devMaintenWorkService.Auxiliary(id);
        return R.ok().put("i", i);
    }

    @RequestMapping("/update8d")
    @ResponseBody
    @AutoLog("添加8d后，流程结束")
    public R update8d(String id) {
        int i = devMaintenWorkService.update8D(id);
        return R.ok().put("i", i);
    }

    /**
     * 催办保存
     *
     * @param devReportUrge
     * @return
     */
    @RequestMapping("/urgeSave")
    @ResponseBody
    @RequiresPermissions("devmaintenwork:urge")
    public R urgeSave(@RequestBody DevReportUrgeEntity devReportUrge) {
        return deviceRepairManager.urge(devReportUrge.getRepairNo(), ShiroUtils.getUserId()) ? R.ok() : R.error();
    }

    /**
     * 导入设备维修记录
     */
    @RequestMapping("/imports")
    @RequiresPermissions("devmaintenwork:export")
    @ResponseBody
    public R imports(@RequestParam("file") MultipartFile file) throws Exception {
        int num = devMaintenWorkService.batchImport(file);
        return R.ok("成功导入" + num + "记录");
    }

}
